﻿using System.Reflection;
using RpcHelper;
using Unity;
using Unity.Lifetime;

namespace RpcCentral.Common
{
    public class UnityHelper
    {
        private static readonly IUnityContainer _Container = null;
        private static readonly List<string> _Assemplys = new List<string>();
        private static readonly LockHelper _lock = new LockHelper();
        static UnityHelper()
        {
            _Container = new UnityContainer();
        }

        public static void Init()
        {
            AppDomain.CurrentDomain.AssemblyLoad += CurrentDomain_AssemblyLoad;
            Assembly[] assembly = AppDomain.CurrentDomain.GetAssemblies().FindAll(c => c.GetName().Name.StartsWith("RpcCentral."));
            assembly.ForEach(c => {
                _Reg(c);
            });
        }
        public static void Register(Type form, Type to, string name)
        {
            if (!_Container.IsRegistered(form, name))
            {
                _Container.RegisterType(form, to, name, new TransientLifetimeManager());
            }
        }
        public static void Register(Type form, Type to)
        {
            if (!_Container.IsRegistered(form))
            {
                _Container.RegisterType(form, to,  new TransientLifetimeManager());
            }
        }
        public static void RegisterSingle<T>(T to)
        {
            if (!_Container.IsRegistered<T>())
            {
                _Container.RegisterInstance<T>(to,new ContainerControlledLifetimeManager());
            }
        }
        public static void RegisterSingle(Type form, Type to)
        {
            if (!_Container.IsRegistered(form))
            {
                _Container.RegisterType(form, to, new ContainerControlledLifetimeManager());
            }
        }
        private static void CurrentDomain_AssemblyLoad(object? sender, AssemblyLoadEventArgs args)
        {
            if (args.LoadedAssembly.GetName().Name.StartsWith("RpcCentral."))
            {
                _Reg(args.LoadedAssembly);
            }
        }

        private static void _Reg(Assembly assembly)
        {
            if (_lock.GetLock())
            {
                if (_Assemplys.Contains(assembly.FullName))
                {
                    _lock.Exit();
                    return;
                }
                _Assemplys.Add(assembly.FullName);
                _lock.Exit();
            }
            Type[] types = assembly.GetTypes();
            Type[] list = types.FindAll(c => c.IsInterface && c.IsPublic);
            if (list.IsNull())
            {
                return;
            }
            list.ForEach(c =>
            {
                if (!_Container.IsRegistered(c))
                {
                    Type[] subs = types.FindAll(a => a.GetInterface(c.FullName) != null);
                    if (subs.Length == 1)
                    {
                        _Container.RegisterType(c, subs[0]);
                        _Init(subs[0]);
                    }
                }
            });
        }
        private static void _Init(Type type)
        {
            ConstructorInfo[] list = type.GetConstructors();
            list.ForEach(c =>
            {
                ParameterInfo[] ps = c.GetParameters();
                if (ps.Length > 0 && ps.TrueForAll(a => a.ParameterType.IsInterface))
                {
                    ps.ForEach(a =>
                    {
                        _Reg(a.ParameterType.Assembly);
                    });
                }
            });
        }
        public static T Resolve<T>()
        {
            return _Container.Resolve<T>();
        }
        public static T Resolve<T>(string name)
        {
            return _Container.Resolve<T>(name);
        }
    }
}
